using System;
using AutoBuild.Console;
using AutoBuild.Console.CommandLine;
using AutoBuild.Core;
using AutoBuild.Core.Configuration.Runner;
using AutoBuild.Core.Framework;
using AutoBuild.Runner.NAntRunner;
using Machine.Specifications;
using Rhino.Mocks;

namespace AutoBuild.Specs.Console
{
    [Subject(typeof(CommandLineParser))]
    public class when_passed_the_help_parameter_shows_help : CommandLineParserSpecs
    {
        static Exception Exception;

        Because of = () =>
            Exception = Catch.Exception(() => Subject.Parse(new[] {"--help"}));

        It should_raise_argumentException = () =>
            Exception.ShouldBeOfType<InvalidCommandLineException>();

        It should_contain_help = () =>
            Exception.Message.ShouldStartWith("Usage: " + Environment.NewLine + "AutoBuild.Console [Options]+ [folder] <build-file>");
    }


    [Subject(typeof(CommandLineParser))]
    public class when_the_help_perameter_is_set_it_shows_available_runners : CommandLineParserSpecs
    {
        static Exception Exception;

        Because of = () =>
            Exception = Catch.Exception(() => Subject.Parse(new[] { "--help" }));

        It should_show_available_runners = () =>
        {
            Exception.Message.ShouldContain("Available runners:");
            Exception.Message.ShouldContain("- Runner1");
            Exception.Message.ShouldContain("- Runner2");
        };
    }


    [Subject(typeof(CommandLineParser))]
    public class when_the_help_and_runner_perameter_is_set_it_shows_help_for_runner : CommandLineParserSpecs
    {
        static Exception Exception;

        Because of = () =>
            Exception = Catch.Exception(() => Subject.Parse(new[] { "--help", "-r=X" }));

        It should_show_help_of_selected_runner = () =>
        {
            Exception.Message.ShouldContain("-p, --path=PATH");
            Exception.Message.ShouldContain("PATH for test");
            Exception.Message.ShouldContain("-a, --args=ARGS");
            Exception.Message.ShouldContain("The ARGS to test");
        };
    }
    
    [Subject(typeof(CommandLineParser))]
    public class when_the_runner_perameter_is_set_the_arguments_are_set : CommandLineParserSpecs
    {
        static CommandLineAutoBuildArguments BuildArguments;

        Because of = () =>
            BuildArguments = Subject.Parse(new[] {"-r=X", "-p=c:\\temp\\foo.txt", "--args='-t -f:net-4.0'"});

        It should_show_help_of_selected_runner = () =>
        {
            BuildArguments.RunnerName.ShouldEqual("X");
            BuildArguments.RunnerArgument.ShouldBe(typeof(FooOptions));

            FooOptions fooOptions = BuildArguments.RunnerArgument as FooOptions;
            fooOptions.Args.ShouldEqual("'-t -f:net-4.0'");
            fooOptions.Foo.ShouldEqual("c:\\temp\\foo.txt");
        };
    }




    //--------------------------------------------------------- 
    public abstract class CommandLineParserSpecs : Specification<CommandLineParser>
    {
        protected static IConsole Console { get; private set; }
        protected static IBuildRunner Runner1 { get; private set; }
        protected static IBuildRunner Runner2 { get; private set; }
        protected static IBuildRunner<FooOptions> RunnerWithOptions { get; private set; }

        Establish context = () =>
        {
            Console = Mock<IConsole>();
            Runner1 = Mock<IBuildRunner>();
            Runner2 = Mock<IBuildRunner>();
            RunnerWithOptions = Mock<IBuildRunner<FooOptions>>();

            Runner1.Expect(x => x.RunnerName).Return("Runner1").Repeat.AtLeastOnce();
            Runner2.Expect(x => x.RunnerName).Return("Runner2").Repeat.AtLeastOnce();
            RunnerWithOptions.Expect(x => x.RunnerName).Return("X").Repeat.AtLeastOnce();
            RunnerWithOptions.Expect(x => x.RunnerOptionsType).Return(typeof (FooOptions));
            
            Subject = new CommandLineParser( new RunnerSelector( new[] { Runner1, Runner2, RunnerWithOptions }), Console );
        };

        
    }
    public class FooOptions
    {
        [CommandLineOption(Name = "p|path=", Description = "{PATH} for test")]
        public string Foo { get; set; }

        [CommandLineOption(Name = "a|args=", Description = "The {ARGS} to test")]
        public string Args { get; set; }
    }
}